/*
 * Copyright (c) 2016 CGT Co., Ltd.
 *
 * Authors: Robin Lee <lixiangbin@china-dsp.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program;
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <memory.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <sys/time.h>
#include <sys/socket.h>

#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <math.h>
#include <unistd.h>
#include <signal.h>

#include <termios.h>
#include <netinet/in.h>

/*---------------------------------------------------------------------------------------------------------------------------------------------------
 * global vars
 */
#define FP_DEV1 "/sys/class/i2c-dev/i2c-0/device/0-0001/eeprom"
#define FP_DEV2 "/sys/class/i2c-dev/i2c-0/device/0-0002/eeprom"
#define FP_DEV3 "/sys/class/i2c-dev/i2c-0/device/0-0004/eeprom"

static int global_fd1 = -1;
static int global_fd2 = -1;
static int global_fd3 = -1;

//operations of sdi
//open fd
int fd_initial(int num)
{
	int fd = -1;
	/*
		Open modem device for reading and writing and not as controlling tty
		because we don't want to get killed if linenoise sends CTRL-C.
	*/
	if(num==0)
	{
//		printf("Open '%s' .. ", FP_DEV1);
		fd = open(FP_DEV1, O_RDWR );
	}
	else if(num==1)
	{
//		printf("Open '%s' .. ", FP_DEV2);
		fd = open(FP_DEV2, O_RDWR );
	}
	else if(num==2)
	{
//		printf("Open '%s' .. ", FP_DEV3);
		fd = open(FP_DEV3, O_RDWR );
	}
	else
	{
		printf("Open error.\n");
		return -1;
	}

	if (fd <0) {
		printf("failed (err = %d)\n", fd);
		return -1;
	}
//	printf("Done\n");
	return fd;
}

//close fd
int fd_exit(int num)
{
	if(num==0)
	{
		close(global_fd1);
//		printf("Close '%s' .. ", FP_DEV1);
	}
	else if(num==1)
	{
		close(global_fd2);
//		printf("Close '%s' .. ", FP_DEV2);
	}
	else if(num==2)
	{
		close(global_fd3);
//		printf("Close '%s' .. ", FP_DEV3);
	}
//	printf("Done\n");
	return 0;
}

/*---------------------------------------------------------------------------------------------------------------------------------------------------
 * get_sdi_reg, set_sdi_reg
 */
//get sdi reg by i2c
unsigned int get_sdi_reg(int num,unsigned int offset)
{
	unsigned int value = 0xffff;
	unsigned int ans=0;
	int fd=-1;
	if(num==0)
	{
		fd=global_fd1;
	}
	else if(num==1)
	{
		fd=global_fd2;
	}
	else if(num==2)
	{
		fd=global_fd3;
	}
	else
	{
		printf("get_sdi_reg::Invalid param !\n");
		return 0;
	}

	if (fd<0) {
		printf("Invalid device handle !\n");
		return value;
	}

	if( lseek(fd, offset, SEEK_SET) == (off_t) -1 ) {
		printf("failed for seek to offset 0x%x !\n", offset);
		return value;
	}

	if ( read(fd, &value, sizeof(value)) != sizeof(value)) {
		printf("failed for read from offset 0x%x !\n", offset);
		return value;
	}
	ans=htonl(value);
	return ans;
}

//set sdi reg by i2c
void set_sdi_reg(int num,unsigned int offset, unsigned int data)
{
	unsigned int value = htonl(data);
	int fd=-1;
	if(num==0)
	{
		fd=global_fd1;
	}
	else if(num==1)
	{
		fd=global_fd2;
	}
	else if(num==2)
	{
		fd=global_fd3;
	}
	else
	{
		printf("set_sdi_reg::Invalid param !\n");
		return;
	}
	if (fd<0) {
		printf("Invalid device handle !\n");
		return ;
	}

	if( lseek(fd, offset, SEEK_SET) == (off_t) -1 ) {
		printf("failed for seek to offset 0x%x !\n", offset);
		return ;
	}

	if ( write(fd, &value, sizeof(value)) != sizeof(value)) {
		printf("failed for write from offset 0x%x !\n", offset);
		return ;
	}
	return ;
}

unsigned int regtoul(const char *str)
{
	int cbase = 10;
	if(str[0]=='0'&&(str[1]=='x'||str[1]=='X')) {
		cbase = 16;
	}
	return strtoul(str, NULL, cbase);
}

//init sdi
int Init_sdi(int num)
{
	if(num==0)
	{
		global_fd1 = fd_initial(0);
	}
	else if(num==1)
	{
		global_fd2 = fd_initial(1);
	}
	else if(num==2)
	{
		global_fd3 = fd_initial(2);
	}
	return 0;
}

int higher2lower(char c)
{
	if(c >= 'A' && c <= 'Z')
		return c + 'a' - 'A';
	else
	  return c;
}

int htoi(char s[])
{
	int i;
	int n = 0;
	if(s[0] == '0' && (s[1] == 'x' || s[1] == 'x'))
	  i = 2;
	else
	  i = 0;
	for(;(s[i] >= '0' && s[i] <= '9') || (s[i] >= 'a' && s[i] <= 'f') \
			|| (s[i] >= 'A' && s[i] <= 'F'); ++i)
	{
		if(higher2lower(s[i] > '9'))
		{
			n = 16 * n +(10 + higher2lower(s[i]) - 'a');
		}
		else
		  n = 16 * n + (higher2lower(s[i] - '0'));
	}
	return n;
}


int main(int argc, char **argv)
{
	int baseaddr=0;
	int offset=0;
	int port=0;
	int temp1=0,temp2=0,temp3=0,temp4=0;
	int writeval=0;
	int val=0;
	int true_offset=0;
	int read_val=0;

	unsigned int sdi_index;



	if(argc < 10)
	{
		printf("input error\n");
		exit(1);
	}
	baseaddr = strtoul(argv[1], 0, 0);
	offset = strtoul(argv[2], 0, 0);
	port = strtoul(argv[3], 0, 0);

	temp1 = strtoul(argv[4], 0, 0);
	temp2 = strtoul(argv[5], 0, 0);
	temp3 = strtoul(argv[6], 0, 0);
	temp4 = strtoul(argv[7], 0, 0);

	writeval = strtoul(argv[8], 0, 0);
	val= strtoul(argv[9], 0, 0);
	sdi_index=htoi(argv[10]);


	Init_sdi(sdi_index);
	true_offset=baseaddr+offset*port+temp1*temp2+temp3*temp4;

	if(val==1)
	{
		read_val=get_sdi_reg(sdi_index,true_offset);
		printf("read value is 0x%x\n",read_val);
	}
	else
	{
		set_sdi_reg(sdi_index,true_offset,writeval);
	}

	fd_exit(sdi_index);

	return 0;
}
